package Ants.Modules.Fight.Minimax;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import Ants.Model.Alert;
import Ants.Model.Status;
import Ants.Modules.Fight.Minimax.Model.Ant;
import Ants.Modules.Fight.Minimax.Model.Tile;

public class MinimaxStatus {

	private int level;
	private int value;

	private List<Ant> myAnts;
	private List<Ant> enemiesAnts;
	private Alert alert;

	public MinimaxStatus( Alert alert, List<Ant> myAnts, List<Ant> enemiesAnts){
		this.alert = alert;
		this.myAnts = myAnts;
		this.enemiesAnts = enemiesAnts;
	}

	//Tutti gli stati raggiungibili dal giocatore Max, muovendo le myAnts
	public List<MinimaxStatus> getSussessorsMax(){

		MinimaxStatusUtils utils = new MinimaxStatusUtils(false, enemiesAnts);
		List<List<Ant>> allMoves = utils.getAllMoves(myAnts);
		
		List<MinimaxStatus> sussessors = new ArrayList<MinimaxStatus>(allMoves.size());
		
		for (List<Ant> moves : allMoves) {
			sussessors.add(new MinimaxStatus(alert, moves, enemiesAnts));
		};

		return sussessors;
	}

	//Tutti gli stati raggiungibili dal giocatore Min, muovendo le enemiesAnts
	public List<MinimaxStatus> getSussessorsMin(){

		MinimaxStatusUtils utils = new MinimaxStatusUtils(true, myAnts);
		List<List<Ant>> allMoves = utils.getAllMoves(enemiesAnts);
		
		List<MinimaxStatus> sussessors = new ArrayList<MinimaxStatus>(allMoves.size());
		
		for (List<Ant> moves : allMoves) {
			sussessors.add(new MinimaxStatus(alert, myAnts, moves));
		};
		
		return sussessors;
	}

	public int getLevel(){
		return level;
	}

	public void setLevel(int level){
		this.level = level;
	}

	public void setValue(int value) {
		this.value = value;
	}

	public int getValue(){
		return value;
	}

	public List<Ant> getMyAnts() {
		return myAnts;
	}

	public List<Ant> getEnemiesAnts() {
		return enemiesAnts;
	}

	@Override
	public String toString() {
		return String.format("Friends: %s - Enemies: %s", myAnts, enemiesAnts);
	}

	public void calculateAntsDistances(){
		calculateCloseEnemiesAnts(myAnts,enemiesAnts);
		
		HashMap<Integer, List<Ant>> dic = new HashMap<Integer, List<Ant>>();
		
		for (Ant ant : enemiesAnts) {
			List<Ant> list = dic.get(ant.getId());
			if(list == null)
				list = new ArrayList<Ant>();
			list.add(ant);
			dic.put(ant.getId(), list);
		}
		
		for (Integer id : dic.keySet()){
			List<Ant> enemy = new ArrayList<Ant>();
			enemy.addAll(myAnts);
			for (Integer i : dic.keySet()){
				if(i != id)
					enemy.addAll(dic.get(i));
			}
			calculateCloseEnemiesAnts(dic.get(id),enemy);
		}
	}
	
	public void calculateFoodDistances(){
		List<Ant> ants = new ArrayList<Ant>();
		ants.addAll(myAnts);
		ants.addAll(enemiesAnts);
		for (Ant ant : ants){
			ant.setCloseFoodDist(Integer.MAX_VALUE);
			for (Ants.Model.Tile f : alert.getFood()) {
				Tile food = new Tile(f.getRow(),f.getCol());
				int distRow = Tile.GetDistRow(ant.getTile(),food);
				int distCol = Tile.GetDistCol(ant.getTile(),food);
				int dist = (distRow*distRow) + (distCol*distCol);
				
				if(dist<ant.getCloseFoodDist())
					ant.setCloseFoodDist(dist);
			}
		}
	}

	public void calculateMyDistanceFromEnemyHill(){
		for (Ant ant : myAnts){
			ant.setCloseEnemyHillDist(Integer.MAX_VALUE);
			for (Ants.Model.Tile h : alert.getEnemyHills()){
				Tile hill = new Tile(h.getRow(), h.getCol());
				int distRow = Tile.GetDistRow(ant.getTile(),hill);
				int distCol = Tile.GetDistCol(ant.getTile(),hill);
				int dist = (distRow*distRow) + (distCol*distCol);

				if(dist < ant.getCloseEnemyHillDist())
					ant.setCloseEnemyHillDist(dist);
			}
		}
	}
	
	public void calculateEnemyDistanceFromMyHill(){
		for (Ant ant : enemiesAnts){
			ant.setCloseEnemyHillDist(Integer.MAX_VALUE);
			for (Ants.Model.Tile h : alert.getMyHills()){
				Tile hill = new Tile(h.getRow(), h.getCol());
				int distRow = Tile.GetDistRow(ant.getTile(),hill);
				int distCol = Tile.GetDistCol(ant.getTile(),hill);
				int dist = (distRow*distRow) + (distCol*distCol);

				if(dist < ant.getCloseEnemyHillDist())
					ant.setCloseEnemyHillDist(dist);
			}
		}
	}

	private void calculateCloseEnemiesAnts(List<Ant> friends, List<Ant> enemies){
		for (Ant ant : friends) {
			ant.setCloseEnemies(new ArrayList<Ant>(enemies.size()));
			ant.setCloseEnemyDist(Integer.MAX_VALUE);
			for (Ant enemy : enemies) {
				int distRow = Tile.GetDistRow(ant.getTile(),enemy.getTile());
				int distCol = Tile.GetDistCol(ant.getTile(),enemy.getTile());
				int dist = (distRow*distRow) + (distCol*distCol);
				
				if(dist < ant.getCloseEnemyDist())
					ant.setCloseEnemyDist(dist);
				
				int radius = Status.AttackRadius2;
				if(dist <= radius)
					ant.getCloseEnemies().add(enemy);
			}
		}
	}

	public Alert getAlert() {
		return alert;
	}

	public void setAlert(Alert alert) {
		this.alert = alert;
	}
		
}
